import { getProjectManager } from "./getProjectManager";
import { MyProjectManager } from "./MyProjectManager";
import * as Cesium from "cesium";
import { positionFromCartesian } from "xbsj-xe2/dist-node/xe2-base-cesium";
import { lbhToXyz, geoHeading } from "xbsj-xe2/dist-node/xe2-base-objects";
import { Vector } from 'xbsj-xe2/dist-node/xe2-math';
import { geoDestination } from "xbsj-xe2/dist-node/xe2-base-objects";



// 根据url地址获取参数
export const getUrlParam = () => {
    let url = window.location.search; /* 获取属性（“?”后面的分段） */
    if (url) {
        let lastUrl = url.slice(1)
        let urlParam = lastUrl.split('&')
        let urlParamObj: { [k: string]: any; } = {}
        urlParam.forEach(item => {
            const newArr = item.split('=')
            // @ts-ignore
            urlParamObj[newArr[0]] = decodeURIComponent(newArr[1])
        })
        return urlParamObj
    } else {
        return ''
    }
}

// 对象中的所有数值保留三位小数
export function roundValues(obj: any) {
    for (let key in obj) {
        if (typeof obj[key] === 'number') {
            // obj[key] = parseFloat(obj[key].toFixed(3));
            // 使用 Math.floor() 方法向下取整
            obj[key] = Math.floor(obj[key] * 1000) / 1000;
        }
    }
    return obj;
}

// 对象中的所有数值保留七位小数
export function roundValues2(obj: any) {
    for (let key in obj) {
        if (typeof obj[key] === 'number') {
            // obj[key] = parseFloat(obj[key].toFixed(3));
            // 使用 Math.floor() 方法向下取整
            obj[key] = Math.floor(obj[key] * 10000000) / 10000000;
        }
        if (key == "minZ" || key == "maxZ") {
            obj[key] = Math.floor(obj[key] * 1000) / 1000;
        }
    }
    return obj;
}

//时间戳转换为时间
export function timestampToTime(hours: any, minute: any) {
    const date = new Date()//获取当前时间
    const year = date.getFullYear(); //获取完整的年份(4位,1970-????)
    const month = date.getMonth();  //获取当前月份(0-11,0代表1月)
    const date1 = date.getDate();  //获取当前日(1-31)
    // const minutes = date.getMinutes();  //获取当前分钟数(0-59)
    // const seconds = date.getSeconds();  //获取当前秒数(0-59)
    const time = `${year}-${month + 1}-${date1} ${hours < 24 ? hours : '23'}:${hours < 24 ? minute : '59'}:${hours < 24 ? '00' : '59'}`
    return time
}
//时间转换为时间戳
export function timeToTimestamp(time: any) {
    //@ts-ignore
    const times = Date.parse(new Date(time))
    return times
}
export function formatDate(now: number) {
    const time = new Date(now)
    const hour = time.getHours();     //返回日期中的小时数（0到23）
    const minute = time.getMinutes(); //返回日期中的分钟数（0到59）
    return [hour, minute]
}

/**
 * 
 * @param arr 数组
 * @param key 
 * @param o 
 * @param comparator 
 * @returns 
 */
export function findMaxNum(arr: any, key: any, o: any, comparator: Function) {
    for (let i = 1; i < arr.length; i++) {
        if (comparator(arr[i][o], key)) {
            key = arr[i][o]
        }
    }
    return key
}

// 将经纬度转换为弧度
function toRadians(degrees: number) {
    return degrees * Math.PI / 180;
}

/**
 * 使用 海伐线公式 计算两经纬度之间的距离（单位为米）
 * @param lat1 小的纬度
 * @param lon1 小的经度
 * @param lat2 大的纬度
 * @param lon2 大的经度
 * @returns 
 */
export function calculateDistanceInMeters(lat1: number, lon1: number, lat2: number, lon2: number) {
    const earthRadius = 6371; // 地球半径，单位为公里

    const dLat = toRadians(lat2 - lat1);
    const dLon = toRadians(lon2 - lon1);

    const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
        Math.cos(toRadians(lat1)) * Math.cos(toRadians(lat2)) *
        Math.sin(dLon / 2) * Math.sin(dLon / 2);

    const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

    const distanceInKm = earthRadius * c; // 距离，单位为公里
    const distanceInMeters = distanceInKm * 1000; // 转换为米

    return distanceInMeters;
}
/**
 * 
 * @returns 随机颜色
 */
export function getRandomColor() {
    const letters = '0123456789ABCDEF';
    let color = '#';
    for (let i = 0; i < 6; i++) {
        color += letters[Math.floor(Math.random() * 16)];
    }
    return color;
}
// 获取当天中午十二点的时间戳
export function getNoonTimestamp() {
    // 获取当前日期
    const now = new Date();

    // 设置时间为中午十二点
    now.setHours(12, 0, 0, 0);

    // 返回时间戳
    return now.getTime();
}

//提供一个时间戳，返回一个年月日 时分
export function formatTime(timestamp: any) {
    const date = new Date(timestamp);
    const year = date.getFullYear();
    const month = (date.getMonth() + 1).toString().padStart(2, '0');
    const day = date.getDate().toString().padStart(2, '0');
    const hour = date.getHours().toString().padStart(2, '0');
    const minute = date.getMinutes().toString().padStart(2, '0');
    return `${year}-${month}-${day} ${hour}:${minute}`;
}


//根据类型获取此类型在场景树上的个数
function getsceneObjNumfromSceneTreeFun(obj: { [key: string]: any }, result: any[], type: string) {
    if (obj['sceneObj']) {
        if (obj['sceneObj'].type && obj['sceneObj'].type === type) {
            result.push(1)
        }
    }
    if (obj['children']) {
        for (let i = 0; i < obj['children'].length; i++) {
            getsceneObjNumfromSceneTreeFun(obj['children'][i], result, type);
        }
    }
}
//根据类型获取此类型在场景树上的个数
export function getsceneObjNumfromSceneTree(type: string, sceneTreeType: any): number {
    const objm = getProjectManager()
    let result: any[] = [];
    const sceneTree = sceneTreeType
    if (sceneTree && sceneTree.json.root.children) {
        getsceneObjNumfromSceneTreeFun(sceneTree.json.root, result, type);
    }
    return result.length
}

// 计算两个经纬度点之间的插值点
export const computeInterpolationPoints = (point1: [number, number, number], point2: [number, number, number], gap: number) => {
    const start = Cesium.Cartesian3.fromDegrees(...point1);
    const end = Cesium.Cartesian3.fromDegrees(...point2);
    const temp = []
    const normal = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
    const length = Cesium.Cartesian3.distance(start, end);
    Cesium.Cartesian3.normalize(normal, normal);
    for (let i = 0; i <= Math.floor(length / gap); i++) {
        const temp1 = i == 0 ? positionFromCartesian(start) : positionFromCartesian(Cesium.Cartesian3.add(start, Cesium.Cartesian3.multiplyByScalar(normal, i * gap, new Cesium.Cartesian3()), new Cesium.Cartesian3()))
        if (temp1)
            temp.push(temp1);
    }
    //@ts-ignore
    // temp.push(positionFromCartesian(end));
    return temp;
}

// 计算两个经纬度点之间的 hpr
export const computeRot = (point1: [number, number, number], point2: [number, number, number]) => {
    const lp = [...point1] as [number, number, number];
    const rp = [...point2] as [number, number, number];
    const lc = lbhToXyz(lp);
    const rc = lbhToXyz(rp);
    const distance = Vector.distance(lc, rc);
    if (distance === 0) {
        return [0, 0, 0];
    }

    const heading = geoHeading(lp, rp);
    const height = rp[2] - lp[2];
    const pitch = Math.asin(height / distance) * 180 / Math.PI;

    const h = Number.isFinite(heading) ? heading : 0;
    const p = Number.isFinite(pitch) ? pitch : 0;
    return [h, 0, 0];
}

export function getPints(pointsLLH: [number, number, number][], step: number = 2): [number, number, number][] {
    let getIntersectionImpl = (start: Cesium.Cartesian3, end: Cesium.Cartesian3, next: Cesium.Cartesian3, normal: Cesium.Cartesian3, step: number) => {
        if (!next) return false;
        const left = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
        const right = Cesium.Cartesian3.subtract(next, end, new Cesium.Cartesian3())
        const leftLength = Cesium.Cartesian3.magnitude(left);
        const projectionVector = Cesium.Cartesian3.projectVector(left, right, new Cesium.Cartesian3());
        Cesium.Cartesian3.normalize(left, left);
        Cesium.Cartesian3.normalize(right, right);
        const dot = Cesium.Cartesian3.dot(left, right);
        if (1 - Math.abs(dot) < 0.000001) {
            // 平行，直接取值,然后替换下一个起始点
            return Cesium.Cartesian3.add(start, Cesium.Cartesian3.multiplyByScalar(normal, step, new Cesium.Cartesian3()), new Cesium.Cartesian3());
        } else {
            //不平行，通过向量计算相邻点，找到相邻点后，替换下一个起始点
            const projectionLength = Cesium.Cartesian3.magnitude(projectionVector);
            const needVectorLength = Math.sqrt(step ** 2 - leftLength ** 2 + projectionLength ** 2);
            const nextNormal = Cesium.Cartesian3.subtract(next, end, new Cesium.Cartesian3());
            Cesium.Cartesian3.normalize(nextNormal, nextNormal);//方向向量归一化
            // 交点
            const intersection = Cesium.Cartesian3.add(
                end,
                Cesium.Cartesian3.multiplyByScalar(nextNormal, needVectorLength + (dot < 0 ? projectionLength : -projectionLength), new Cesium.Cartesian3()),
                new Cesium.Cartesian3()
            )
            if (isNaN(intersection.x) || isNaN(intersection.y) || isNaN(intersection.z)) return false;
            // 判断交点是否在线上，在线上返回点，不在返回false
            const distance = Cesium.Cartesian3.distance(intersection, end);
            const distance2 = Cesium.Cartesian3.distance(end, next);
            if (distance > distance2) return false;
            const v1 = Cesium.Cartesian3.subtract(intersection, end, new Cesium.Cartesian3());
            const v2 = Cesium.Cartesian3.subtract(next, end, new Cesium.Cartesian3());
            const dot2 = Cesium.Cartesian3.dot(v1, v2);
            if (dot2 < 0) return false;
            return intersection;
        }
    }
    let getIntersection = (points: Cesium.Cartesian3[], start: Cesium.Cartesian3, end: number, normal: Cesium.Cartesian3, step: number) => {
        if (points.length == end + 1) return points;
        const intersection = getIntersectionImpl(start, points[end], points[end + 1], normal, step);
        if (intersection instanceof Cesium.Cartesian3) {
            points[end] = intersection;
            return points;
        } else {
            // 都不符合，后续点删没了，直接返回
            points.splice(end, 1);
            return getIntersection(points, start, end, normal, step);
        }
    }
    let points = [];
    const result = [] as [number, number, number][];
    // 经纬度转笛卡尔坐标
    for (let i = 0; i < pointsLLH.length; i++) {
        const element = pointsLLH[i];
        points.push(Cesium.Cartesian3.fromDegrees(...element))
    }
    for (let j = 0; j < points.length; j++) {
        const start = points[j];
        const end = points[j + 1];
        if (!end) break;
        const normal = Cesium.Cartesian3.subtract(end, start, new Cesium.Cartesian3());
        const length = Cesium.Cartesian3.distance(start, end);
        Cesium.Cartesian3.normalize(normal, normal);//方向向量归一化
        for (let i = 0; i <= Math.floor(length / step); i++) {
            const interpolationPoint = Cesium.Cartesian3.add(start, Cesium.Cartesian3.multiplyByScalar(normal, i * step, new Cesium.Cartesian3()), new Cesium.Cartesian3());
            const tempPos = i == 0 ? positionFromCartesian(start) : positionFromCartesian(interpolationPoint)
            if (tempPos)
                result.push(tempPos);
            if (i == Math.floor(length / step)) {
                // 最后一个点，找下一段线的交点
                points = getIntersection(points, interpolationPoint, j + 1, normal, step);
            }
        }
    }
    return result;
}

// 生成随机颜色
export function getRandomHexColor() {
    // 生成一个0到255之间的随机整数，并将其转换为16进制字符串
    const toHex = (c: any) => {
        const hex = c.toString(16);
        return hex.length == 1 ? "0" + hex : hex;
    };

    // 生成三个0到255之间的随机整数，分别代表红、绿、蓝
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);

    // 将这三个整数转换为16进制字符串，并拼接在一起
    return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}


export function scientificToDecimal(num: any) {
    if (isNaN(num)) {
        return num
    }
    num = '' + num
    num = parseFloat(num)
    let eformat = num.toExponential() // 转换为标准的科学计数法形式（字符串）
    let tmpArray = eformat.match(/\d(?:\.(\d*))?e([+-]\d+)/)  // 分离出小数值和指数值
    // @ts-ignore
    let number = num.toFixed(Math.max(0, (tmpArray[1] || '').length - tmpArray[2]))
    return Number(number)
}


// export function getOffsetPoints(point: [number, number, number], rotation: [number, number, number], offset: number) {
//     let normal = Cesium.Cartesian3.fromArray(getDirectionVector(rotation))
//     const endCartesian3 = Cesium.Cartesian3.add(
//         Cesium.Cartesian3.fromDegrees(...point),
//         Cesium.Cartesian3.multiplyByScalar(normal, offset, new Cesium.Cartesian3()), new Cesium.Cartesian3());
//     return positionFromCartesian(endCartesian3);
// }

// 旋转角转方向向量
export function getDirectionVector(rotation: [number, number, number]) {
    const heading = Cesium.Math.toRadians(rotation[0]);
    const pitch = Cesium.Math.toRadians(rotation[1]); // 将角度转换为弧度
    const roll = Cesium.Math.toRadians(rotation[2]);
    // 创建一个Matrix3来表示俯仰、偏航和滚转角
    const rotationMat3 = Cesium.Matrix3.fromHeadingPitchRoll(new Cesium.HeadingPitchRoll(heading, pitch, roll));
    // 获取方向向量
    const direction = new Cesium.Cartesian3();
    Cesium.Matrix3.multiplyByVector(rotationMat3, Cesium.Cartesian3.UNIT_X, direction);
    return [direction.x, direction.y, direction.z] as [number, number, number];
}

export function getOffsetPoints(point: [number, number, number], rotation: [number, number, number], offset: number) {
    {
        const origin = point;
        const distance = offset;
        const groundDistance = distance * Math.cos(rotation[1] * Math.PI / 180);
        const des = geoDestination(origin, groundDistance, rotation[0]);
        if (!des) return origin;
        const height = distance * Math.sin(rotation[1] * Math.PI / 180);
        des[2] += height;
        return des;
    }
}

// 经纬度、角度保留三位有效小数(数组)
export function processArray(arr: any, few: number = 3) {
    // 创建一个新数组来存储处理后的结果
    const result = [];

    // 遍历数组中的每个元素
    for (let i = 0; i < arr.length; i++) {
        // 检查元素是否为整数
        if (Number.isInteger(arr[i])) {
            // 如果是整数，直接添加到结果数组中
            // @ts-ignore
            result.push(arr[i]);
        } else {
            // 如果是小数，保留三位小数并添加到结果数组中
            // @ts-ignore
            result.push(parseFloat(arr[i].toFixed(few)));
        }
    }

    // 返回处理后的结果数组
    return result;
}

// 经纬度、角度保留三位有效小数(单个数)
export function processNum(num: any, few: number = 3) {
    let newNum;
    if (!num) {
        return 0;
    }

    // 检查元素是否为整数
    if (Number.isInteger(num)) {
        // @ts-ignore
        newNum = num;
    } else {
        // @ts-ignore
        newNum = parseFloat(num.toFixed(few))
    }

    return newNum;
}

// 根据id查找className
export function findClassNameById(id: string, tree: any) {
    // 如果树为空，返回空字符串
    if (!tree || tree.length === 0) {
        return '';
    }

    // 遍历树的每个节点
    for (let i = 0; i < tree.length; i++) {
        const node = tree[i];

        // 如果找到匹配的节点，返回 className
        if (node.value === id) {
            return node.label;
        }

        // 如果节点有子节点，递归查找
        if (node.children && node.children.length > 0) {
            const result: any = findClassNameById(id, node.children);
            if (result) {
                return result;
            }
        }
    }

    // 如果没有找到匹配的节点，返回空字符串
    return '';
}

// hex 转 Rgb
export function hexToRgb(hex: any) {
    hex = parseInt(hex.indexOf("#") > -1 ? hex.substring(1) : hex, 16);
    return [hex >> 16, (hex & 0x00ff00) >> 8, hex & 0x0000ff];
};

// Rgba 转 xe2Color
export function cssColorToXe2Color(cssColor: any) {
    return cssColor.map((e: number, i: number) => {
        if (i === 3) {
            return e;
        }
        return e / 255 || 0
    });
};

//  xe2Color 转 Rgba 
export function xe2ColorToCssColor(xe2Color: any) {
    return xe2Color.map((e: number, i: number) => {
        if (i === 3) {
            return e;
        }
        return e * 255 || 0
    });
};

// 取出字符串'rgba(10, 233, 245, 0.4)' 中的数字
export function extractNumbersFromRGBA(rgbaString: string) {
    if (!rgbaString) return [255, 255, 255, 0.4];
    const regex = /\d+(\.\d+)?/g;
    const matches = rgbaString.match(regex);
    return matches ? matches.map(Number) : [];
}

export const acceptsOptions = {
    json: {
      description: 'JSON Files',
      accept: {
        'text/json': '.json',
      },
    },
    js: {
      description: 'JS Files',
      accept: {
        'text/js': '.js',
      },
    },
    txt: {
      description: 'Text Files',
      accept: {
        'text/plain': ['.txt', '.text'],
      },
    },
  }

export async function getSaveFileHandle(type:string, suggestedName:any) {
    // @ts-ignore
    const option = acceptsOptions[type ?? 'json']
    try {
        // @ts-ignore
        const handle = await window.showSaveFilePicker({
            suggestedName: suggestedName ?? `未命名.${type ?? "json"}`,
            types: [option],
        });

        return handle;
    } catch (error) {
        console.warn(`getSaveFileHandle error: ${error}`);
        return undefined;
    }
}

export async function saveFile(handle:any, str:any) { //.js .txt .json都可使用
    const blob = new Blob([str], { type: "text/plain;charset=utf-8", });
    // @ts-ignore
    const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
}

// 随机返回数组中的一个元素
export function getRandomElement(arr:any) {
    if (arr.length === 0) {
        return null; // 如果数组为空，返回null
    }
    const randomIndex = Math.floor(Math.random() * arr.length);
    return arr[randomIndex];
}

